package com.cc.annotation.support;

import com.cc.annotation.MyDate;
import org.springframework.beans.BeanUtils;
import org.springframework.core.MethodParameter;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.SimpleDateFormat;
/**
 * @description: {jsp(表单---string)==========>servlet(request.getParameter()--手动将jsp获取的string实体类中属性参数类型)}
 * @author: 新梦想.陈超
 * @date:  2022/5/3 下午4:20
 * @version: v1.0
 **/
public class MyHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver{
    private String[] params;  /*属性*/
    private String pattern;   /*日期的格式*/
    //表单中传入birthday参数到controller的参数User的birthday，如何转换
    @Override
    public Object resolveArgument(MethodParameter methodParam, ModelAndViewContainer arg1, NativeWebRequest webRequest,
            WebDataBinderFactory arg3) throws Exception {
      //1.获取controller方法参数Users user的类型对象
        Object object = BeanUtils.instantiateClass(methodParam.getParameterType());
        //2.获取参数类型对象的类信息(Users类的属性和方法)
        BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
        //3.获取请求对象Request
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
         //4.获取Users类类型对象的所有属性描述(获取Users类的所有属性)
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            //5.得到每个属性的名字(Users类的属性名)，并根据属性名称得到请求参数的值
            String value = request.getParameter(propertyDescriptor.getName());
            //6.判断非空
            if (!StringUtils.isEmpty(value)) {
                //5.得到属性的set方法
                Method writeMethod = propertyDescriptor.getWriteMethod();
                //6.如果set方法为非公有方法，暴力破解
                if (!Modifier.isPublic(writeMethod.getModifiers())) {
                    writeMethod.setAccessible(true);
                }
                //7.判断属性名是否为Date指定的params值，如果是params指定值 则进行日期转换
                if (propertyDescriptor.getName().equals(params[0])) {//日期属性
                    SimpleDateFormat sdf = new SimpleDateFormat(this.pattern);
                    java.util.Date date = sdf.parse(value);
                    //调用setBirthday(date)
                    writeMethod.invoke(object, date);
                } else {//非日期的属性
                    //属性类型为Integer
                    if(propertyDescriptor.getPropertyType().equals(Integer.class)) {
                        writeMethod.invoke(object, Integer.parseInt(value));
                     //属性类型为字符串
                    }else {
                        writeMethod.invoke(object, value);
                    }
                }
            }
        }
        return object;
    }

    
    //哪些参数才需要调用我们上面的解析方法进行解析
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        //1、判断controller方法上是否有MyDate注解
        boolean hasParameterAnnotation = parameter.hasParameterAnnotation(MyDate.class);
        if (!hasParameterAnnotation) {
            //不会进入下面的resolveArgument方法进行参数的解析
            return false;
        }
        //2、获取Date注解对象
        MyDate parameterAnnotations = parameter.getParameterAnnotation(MyDate.class);
        //3、获取Date注解的params参数
        String[] parameters = parameterAnnotations.params();
        if (!StringUtils.isEmpty(parameters)) {
            params = parameters;
            //4.获取Date注解的pattern参数
            pattern = parameterAnnotations.pattern();
          //进入下面的resolveArgument方法进行参数的解析
            return true;
        }
        return false;
    }

}















